const express = require('express');
const multer = require('multer');
const fs = require('fs');
const request = require('request');
const app = express();
const upload = multer({ dest: 'uploads/' });
app.use(express.json());
app.use(express.static('www'));

const COZE_TOKEN = 'Bearer pat_3ICHWVah8dPCa43UFvx41NIIbU2X6CpLTAhNpoTrgSs5MMJvBRe0sAW0gXgfA3oQ';//Bearer pat_6CERY6Xkh5e3VX4gE5VZvrlJAWQNxEZwRrjVwnqXDOlrzRdQ10QLGt1mMup1Jjnn';
const BOT_ID = '7494498205476995087';//7494186102418030602';
const USER_ID = 'caiyingkouzi';

const crypto = require('crypto');
const CACHE_FILE = 'file_cache.json';

function getFileMD5(filePath) {
  return new Promise((resolve, reject) => {
    const hash = crypto.createHash('md5');
    const stream = fs.createReadStream(filePath);
    stream.on('data', data => hash.update(data));
    stream.on('end', () => resolve(hash.digest('hex')));
    stream.on('error', reject);
  });
}

function readCache() {
  try {
    if (fs.existsSync(CACHE_FILE)) {
      return JSON.parse(fs.readFileSync(CACHE_FILE, 'utf8'));
    }
    return {};
  } catch (e) {
    return {};
  }
}

function writeCache(cache) {
  fs.writeFileSync(CACHE_FILE, JSON.stringify(cache), 'utf8');
}

async function uploadImage(filePath) {
  const md5 = await getFileMD5(filePath);
  const cache = readCache();
  
  if (cache[md5]) {
    return cache[md5];
  }
  
  return new Promise((resolve, reject) => {
    const options = {
      method: 'POST',
      url: 'https://api.coze.cn/v1/files/upload',
      headers: { 'Authorization': COZE_TOKEN },
      formData: {
        file: {
          value: fs.createReadStream(filePath),
          options: { filename: filePath, contentType: null }
        }
      }
    };
    request(options, (error, response) => {console.log('xxxxxxxx', response.body);
      if (error) return reject(error);
      try {
        const body = JSON.parse(response.body);
        const fileId = body.data.id;
        cache[md5] = fileId;
        writeCache(cache);
        resolve(fileId);
      } catch (e) { reject(e); }
    });
  });
}

function sendQuestion(file_id, text) {
  return new Promise((resolve, reject) => {
    const contentArr = [];
    if (text) contentArr.push({ type: 'text', text: text + '。注意是要生成针对左侧聊天对方的回复' });
    if (file_id) contentArr.push({ type: 'image', file_id });
    const options = {
      method: 'POST',
      url: 'https://api.coze.cn/v3/chat?conversation_id',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': COZE_TOKEN
      },
      body: JSON.stringify({
        bot_id: BOT_ID,
        user_id: USER_ID,
        stream: false,
        additional_messages: [{
          role: 'user',
          content_type: 'object_string',
          content: JSON.stringify(contentArr)
        }]
      })
    };
    request(options, (error, response) => {console.log('yyyyyyyy', response.body);
      if (error) return reject(error);
      try {
        const body = JSON.parse(response.body);
        const { conversation_id, id } = body.data;
        resolve({ conversation_id, chat_id:id });
      } catch (e) { reject(e); }
    });
  });
}

function getAnswer(conversation_id, chat_id) {
  return new Promise((resolve, reject) => {
    function poll() {
      const options = {
        method: 'GET',
        url: `https://api.coze.cn/v3/chat/message/list?conversation_id=${conversation_id}&chat_id=${chat_id}`,
        headers: { 'Authorization': COZE_TOKEN }
      };
      request(options, (error, response) => {console.log('zzzzzzzz', response.body);
        if (error) return reject(error);
        try {
          const body = JSON.parse(response.body);
          if (!body.data) return setTimeout(poll, 1000);
          
          const endMsgIndex = (body.data || []).findIndex(msg => msg.type === 'verbose' && JSON.parse(msg.content).msg_type == 'generate_answer_finish');
          if (endMsgIndex>0) {
            const answerMsg = body.data[endMsgIndex-1];
            resolve(answerMsg.content);
          } else {
            setTimeout(poll, 1000);
          }
        } catch (e) { reject(e); }
      });
    }
    poll();
  });
}

app.post('/coze', upload.single('image'), async (req, res) => {
  try {
    let file_id = null;
    if (req.file) {
      file_id = await uploadImage(req.file.path);
      fs.unlink(req.file.path, () => {});
    }
    const text = req.body.text || '';
    const { conversation_id, chat_id } = await sendQuestion(file_id, text);
    const answer = await getAnswer(conversation_id, chat_id);
    res.end(answer);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

app.listen(3000, () => {
  console.log('Coze代理服务已启动，端口3000');
});